package io.github.echarts.model.context;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;

/**
 * 数据特征提取器
 * <p>
 * 负责从图表数据中提取统计特征和模式，
 * 用于在配置处理和布局计算过程中做出数据驱动的决策。
 * </p>
 */
public class DataFeatureExtractor {

    /**
     * 从数值数组中提取统计特征
     * 
     * @param values 数值数组
     * @param context 配置上下文，用于存储提取的特征
     */
    public static void extractFeatures(Number[] values, ConfigurationContext context) {
        if (values == null || values.length == 0) {
            return;
        }
        
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        stats.reset();  // 重置统计信息
        
        // 收集所有有效的数值
        List<Double> validValues = new ArrayList<>();
        for (Number value : values) {
            if (value != null) {
                double doubleValue = value.doubleValue();
                validValues.add(doubleValue);
                stats.updateWithValue(doubleValue);
            }
        }
        
        // 如果没有有效值，直接返回
        if (validValues.isEmpty()) {
            return;
        }
        
        // 计算中位数
        calculateMedian(validValues, stats);
        
        // 标记数据特性
        markDataFeatures(stats, context);
    }
    
    /**
     * 从二维数组中提取统计特征
     * 
     * @param values 二维数组
     * @param context 配置上下文
     */
    public static void extractFeatures(Number[][] values, ConfigurationContext context) {
        if (values == null || values.length == 0) {
            return;
        }
        
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        stats.reset();  // 重置统计信息
        
        // 收集所有有效的数值
        List<Double> validValues = new ArrayList<>();
        for (Number[] row : values) {
            if (row != null) {
                for (Number value : row) {
                    if (value != null) {
                        double doubleValue = value.doubleValue();
                        validValues.add(doubleValue);
                        stats.updateWithValue(doubleValue);
                    }
                }
            }
        }
        
        // 如果没有有效值，直接返回
        if (validValues.isEmpty()) {
            return;
        }
        
        // 计算中位数
        calculateMedian(validValues, stats);
        
        // 标记数据特性
        markDataFeatures(stats, context);
    }
    
    /**
     * 从命名值对象中提取统计特征
     * 
     * @param namedValues 命名值对象列表
     * @param valueKey 值字段的键名
     * @param nameKey 名称字段的键名
     * @param context 配置上下文
     */
    @SuppressWarnings("unchecked")
    public static void extractFeatures(List<Map<String, Object>> namedValues, String valueKey, String nameKey, ConfigurationContext context) {
        if (namedValues == null || namedValues.isEmpty()) {
            return;
        }
        
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        stats.reset();  // 重置统计信息
        
        // 收集所有有效的数值和类别
        List<Double> validValues = new ArrayList<>();
        Set<String> categories = new HashSet<>();
        
        for (Map<String, Object> item : namedValues) {
            // 处理数值
            if (item.containsKey(valueKey)) {
                Object valueObj = item.get(valueKey);
                if (valueObj instanceof Number) {
                    double doubleValue = ((Number) valueObj).doubleValue();
                    validValues.add(doubleValue);
                    stats.updateWithValue(doubleValue);
                }
            }
            
            // 处理类别
            if (nameKey != null && item.containsKey(nameKey)) {
                Object nameObj = item.get(nameKey);
                if (nameObj != null) {
                    String category = nameObj.toString();
                    if (!categories.contains(category)) {
                        categories.add(category);
                        stats.incrementCategoryCount();
                    }
                }
            }
        }
        
        // 如果没有有效值，直接返回
        if (validValues.isEmpty()) {
            return;
        }
        
        // 计算中位数
        calculateMedian(validValues, stats);
        
        // 标记数据特性
        markDataFeatures(stats, context);
    }
    
    /**
     * 从字符串数组中提取类别信息
     * 
     * @param categories 类别数组
     * @param context 配置上下文
     */
    public static void extractCategoryFeatures(String[] categories, ConfigurationContext context) {
        if (categories == null || categories.length == 0) {
            return;
        }
        
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        
        // 统计不同的类别数量
        Set<String> uniqueCategories = new HashSet<>();
        for (String category : categories) {
            if (category != null && !uniqueCategories.contains(category)) {
                uniqueCategories.add(category);
                stats.incrementCategoryCount();
            }
        }
        
        // 添加类别信息到上下文
        context.addInfo("categories", categories);
        context.addInfo("uniqueCategoryCount", uniqueCategories.size());
    }
    
    /**
     * 计算中位数
     * 
     * @param values 有序的数值列表
     * @param stats 数据统计对象
     */
    private static void calculateMedian(List<Double> values, ConfigurationContext.DataStatistics stats) {
        // 对值进行排序
        Collections.sort(values);
        
        int size = values.size();
        if (size == 0) {
            return;
        }
        
        // 计算中位数
        if (size % 2 == 0) {
            // 偶数个元素，取中间两个的平均值
            double median = (values.get(size / 2 - 1) + values.get(size / 2)) / 2;
            stats.setMedian(median);
        } else {
            // 奇数个元素，取中间值
            double median = values.get(size / 2);
            stats.setMedian(median);
        }
    }
    
    /**
     * 标记数据的特殊特征
     * 
     * @param stats 数据统计对象
     * @param context 配置上下文
     */
    private static void markDataFeatures(ConfigurationContext.DataStatistics stats, ConfigurationContext context) {
        Map<String, Boolean> features = new HashMap<>();
        
        // 检查数据范围特征
        double min = stats.getMin();
        double max = stats.getMax();
        double range = max - min;
        
        features.put("hasNegativeValues", stats.isHasNegativeValues());
        features.put("hasSingleValue", stats.isHasSingleValue());
        features.put("isAllPositive", min >= 0);
        features.put("isAllNegative", max <= 0);
        
        // 检查数据分布特征
        double average = stats.getAverage();
        double median = stats.getMedian();
        features.put("isSkewedRight", average > median);  // 右偏分布
        features.put("isSkewedLeft", average < median);   // 左偏分布
        
        // 检查数据密度特征
        int dataPointCount = stats.getDataPointCount();
        features.put("isHighDensity", dataPointCount > 50);  // 数据点较多
        features.put("isLowDensity", dataPointCount < 10);   // 数据点较少
        
        // 范围特征
        features.put("hasWideRange", range > Math.abs(average) * 2);  // 范围宽
        features.put("hasNarrowRange", range < Math.abs(average) * 0.1 && !stats.isHasSingleValue());  // 范围窄
        
        // 存储特征到上下文
        context.addInfo("dataFeatures", features);
    }
    
    /**
     * 安全地获取数据特征Map
     * 
     * @param context 配置上下文
     * @return 数据特征Map，如果不存在则返回空Map
     */
    @SuppressWarnings("unchecked")
    private static Map<String, Boolean> getDataFeatures(ConfigurationContext context) {
        Object featuresObj = context.getInfo("dataFeatures");
        if (featuresObj == null) {
            return new HashMap<>();
        }
        
        // 如果已经是Map<String, Boolean>类型
        if (featuresObj instanceof Map) {
            try {
                Map<?, ?> mapObj = (Map<?, ?>) featuresObj;
                
                // 检查键是否为String类型，值是否为Boolean类型
                boolean isValidMap = true;
                for (Map.Entry<?, ?> entry : mapObj.entrySet()) {
                    if (!(entry.getKey() instanceof String) || !(entry.getValue() instanceof Boolean)) {
                        isValidMap = false;
                        break;
                    }
                }
                
                if (isValidMap) {
                    return (Map<String, Boolean>) mapObj;
                }
            } catch (Exception e) {
                // 转换失败，返回空Map
            }
        }
        
        return new HashMap<>();
    }
    
    /**
     * 推断适合的图表类型
     * 
     * @param context 配置上下文
     * @return 推断的图表类型
     */
    public static ChartType inferChartType(ConfigurationContext context) {
        ConfigurationContext.DataStatistics stats = context.getDataStatistics();
        
        // 如果已经指定了图表类型，则返回
        if (context.getChartType() != ChartType.UNKNOWN) {
            return context.getChartType();
        }
        
        // 根据数据特性推断图表类型
        Map<String, Boolean> features = getDataFeatures(context);
        if (features.isEmpty()) {
            return ChartType.BAR;  // 默认为柱状图
        }
        
        // 检查是否为类别数据
        int categoryCount = stats.getCategoryCount();
        if (categoryCount > 0) {
            if (categoryCount <= 6 && stats.isHasSingleValue()) {
                return ChartType.PIE;  // 少量类别适合饼图
            } else if (categoryCount > 20) {
                return ChartType.LINE;  // 大量类别适合折线图
            } else {
                return ChartType.BAR;   // 适中数量的类别适合柱状图
            }
        }
        
        // 根据数据点数量推断
        int dataPointCount = stats.getDataPointCount();
        if (dataPointCount > 100) {
            return ChartType.SCATTER;  // 大量数据点适合散点图
        } else if (dataPointCount > 30) {
            return ChartType.LINE;     // 较多数据点适合折线图
        } else {
            return ChartType.BAR;      // 适中数量的数据点适合柱状图
        }
    }
} 